//
//  NSMMotionManager.m
//  Helper
//
//  Created by nsm on 2019/5/13.
//  Copyright © 2019 nani. All rights reserved.
//

#import "NSMMotionManager.h"
#import <CoreMotion/CoreMotion.h>

@interface NSMMotionManager ()
@property (nonatomic, strong) CMMotionManager *manager;
@property (nonatomic, strong) NSOperationQueue *queue;
@end

@implementation NSMMotionManager

+ (instancetype)sharedInstance {
    static NSMMotionManager *instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [self new];
    });
    return instance;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        _timeInterval = 0.03;
        _manager = CMMotionManager.new;
        // 串行、并发
        _queue = [[NSOperationQueue alloc] init];
    }
    return self;
}

- (void)startGyroUpdates:(void (^)(double, double, double))hander {
    if (!_manager.gyroAvailable) return;
    
    _manager.gyroUpdateInterval = _timeInterval;
    @nsm_weak(self)
    [_manager startGyroUpdatesToQueue:_queue withHandler:^(CMGyroData * _Nullable gyroData, NSError * _Nullable error) {
        @nsm_strong(self)
        if (error) {
            [self.manager stopGyroUpdates];
            return;
        }
        
        if (!gyroData) return;
        
        dispatch_sync_on_main_queue(^{
            !hander?:hander(gyroData.rotationRate.x,
                            gyroData.rotationRate.y,
                            gyroData.rotationRate.z);
        });
    }];
}

- (void)startDeviceMotionUpdates:(void (^)(double, double, double))hander {
    if (!_manager.deviceMotionAvailable) return;
    
    _manager.deviceMotionUpdateInterval = _timeInterval;
    @nsm_weak(self)
    [_manager startDeviceMotionUpdatesToQueue:_queue withHandler:^(CMDeviceMotion * _Nullable motion, NSError * _Nullable error) {
        @nsm_strong(self)
        if (error) {
            [self.manager stopDeviceMotionUpdates];
            return;
        }
        
        if (!motion) return;
        
        dispatch_sync_on_main_queue(^{
            !hander?:hander(motion.rotationRate.x,
                            motion.rotationRate.y,
                            motion.rotationRate.z);
        });
    }];
}

- (void)startAccelerometerUpdates:(void (^)(double, double, double))hander {
    if (!_manager.accelerometerAvailable) return;
    
    _manager.accelerometerUpdateInterval = _timeInterval;
    @nsm_weak(self)
    [_manager startAccelerometerUpdatesToQueue:_queue withHandler:^(CMAccelerometerData * _Nullable accelerometerData, NSError * _Nullable error) {
        @nsm_strong(self)
        if (error) {
            [self.manager stopAccelerometerUpdates];
            return;
        }
        
        if (!accelerometerData) return;
        
        dispatch_sync_on_main_queue(^{
            !hander?:hander(accelerometerData.acceleration.x,
                            accelerometerData.acceleration.y,
                            accelerometerData.acceleration.z);
        });
    }];
}

- (void)stopAllUpdates {
    [_manager stopGyroUpdates];
    [_manager stopDeviceMotionUpdates];
    [_manager stopAccelerometerUpdates];
}

@end
